#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "wikiproclib.h"

unsigned int indexkey(char* title) {
	int len = strlen(title);
	if(len == 0) {
		return 0;
	} else if(len == 1) {
		return title[0] << 8;
	} else {
//		printf("%d %d %d\n",
//				(unsigned char)title[0],
//				(unsigned char)title[1],
//				((unsigned char)title[0] << 8) + (unsigned char)title[1]);
		return ((unsigned char)title[0] << 8) + (unsigned char)title[1];
	}
}

id_idx create_id_index(wikipage* pages, int nr_page) {
	int i;
	id_idx ret;
	ret.max = 0;

	for(i = 0; i < nr_page; i++) {
		if(pages[i].id > ret.max) {
			ret.max = pages[i].id;
		}
	}
	printf("\t\t - id key max: %d\n",ret.max);

	ret.ids = malloc( (ret.max + 1) * sizeof(int) );
	memset(ret.ids, 0, (ret.max + 1) * sizeof(int) );

	for(i = 0; i < nr_page; i++) {
		ret.ids[ pages[i].id] = i;
		//printf("page id %d is %d in the array\n", pages[i].id , i);
	}

	return ret;
}

void load_links(wikipage* pages, const int nr_page, int* index, id_idx* idindex, const char* filename) {
	FILE* file;
	int cntr = 0;
	size_t cnt;
	char* line = NULL;
	int lnkcntr = 0;

	file = fopen(filename, "r");
	printf("\t\t - ");

	while(getline(&line, &cnt, file) != -1) {
		char* tab1;
		char* tab2;
		char* to_title;
		int from = atoi(line);
		int namespace;
		wikipage* link_to = NULL;

		int srch = 0;
		int cmp;
		int nrcmp;

		tab1 = strstr(line, "\t");
		tab2 = strstr(tab1 + 1, "\t");
		namespace = atoi(tab1);
		to_title = malloc(strlen(tab2) + 1);
		strcpy(to_title, tab2 + 1);
		to_title[strcspn(to_title, "\n")] = 0;

		unsigned int idxkey = indexkey(to_title);
//		printf("%s - index key: %d\n", to_title, idxkey);
		srch = index[idxkey];

		if(srch == -1) {
			cntr++;
			continue;
		}

		nrcmp = 0;
		cmp = strcmp(to_title, pages[srch].title);
		while((cmp != 0) && srch < nr_page && to_title[0] == pages[srch].title[0]) {
			cmp = strcmp(to_title, pages[srch].title);
			srch ++;
			nrcmp ++;
		}

		//if this link was not found
		if(cmp != 0) {
			continue; //with the next line
		}

//		printf("%d,", nrcmp);
		//now lookup the from id in the id index
		if(idindex -> ids[from] != 0) {
			int fromidx = idindex -> ids[from];
			pages[srch].nroflinks ++;
			if(pages[srch].alloclinks < pages[srch].nroflinks) {
				pages[srch].alloclinks = pages[srch].nroflinks * 2;
				pages[srch].links = realloc(pages[srch].links, pages[srch].alloclinks * sizeof(int));
			}
			pages[srch].links[pages[srch].nroflinks - 1] = fromidx;
			//printf(" %d (%s) <- %d (%s) \n", pages[srch].id, pages[srch].title, pages[fromidx].id, pages[fromidx].title);
			lnkcntr++;
		}

		cntr++;
		if(cntr % 10000 == 0) {
			printf( cntr % 1000000 == 0 ? "o - %d \n\t\t" : cntr % 100000 == 0 ? "|" : ".", lnkcntr);
			fflush(stdout);
		}
		free(to_title);
	}
	printf(" %d lines processed, %d links\n", cntr, lnkcntr);
	fclose(file);
}


void load_categories(wikipage* pages, const int nr_page, const char* filename) {

}

wikipage* load_pages(const char* filename, int* index, int* nr_pages) {
	FILE* file;
	unsigned char curchr = '_';
	char* line = NULL;
	size_t cnt;
	wikipage* pages;
	long sz = 1024;
	int cntr = 0;

	pages = malloc(sizeof(wikipage) * sz);

	file = fopen(filename, "r");

	printf("\t\t - ");
	while (getline(&line, &cnt, file) != -1) {
		char* tab1;
		char* tab2;
		char* tab3;
		char* tab4;
		if(cntr % 10000 == 0) {
			printf(".");
		}
		if(cntr >= sz) {
			sz = sz + 1024;
			pages = realloc(pages, sizeof(wikipage) * sz);
		}
		tab1 = strstr(line,"\t");
		tab2 = strstr(tab1 + 1,"\t");
		tab3 = strstr(tab2 + 1,"\t");
		tab4 = strstr(tab3 + 1,"\t");
		pages[cntr].id = atoi(line);
		pages[cntr].namespace = atoi(tab1);
		pages[cntr].title = malloc( strcspn(tab2 + 1, "\t") +1 );
		pages[cntr].len = atoi(tab3);
		pages[cntr].nroflinks = 0;
		pages[cntr].alloclinks = 8;
		pages[cntr].links = malloc(8 * sizeof(int));
		pages[cntr].loc.x = random() % 1000 - 500;
		pages[cntr].loc.y = random() % 1000 - 500;
		pages[cntr].loc.z = random() % 1000 - 500;
		strncpy(pages[cntr].title, tab2 + 1, strcspn(tab2 + 1, "\t"));

		//check title index
		unsigned int idxkey = indexkey(pages[cntr].title);
//		printf("%s\n",pages[cntr].title);
		if(idxkey > 0 && index[idxkey] == -1) {
			index[idxkey] = cntr;
		}

		cntr ++;
	}
	printf(" %d pages\n", cntr);
	*nr_pages = cntr;

	fclose(file);

	return pages;
}

float distance(loc loc1, loc loc2) {
	return length(vector(loc1, loc2));
}

loc repulsion(loc sun, loc planet) {
	loc ret = vector(planet, sun);
	if(length(ret) > REPULSION_DISTANCE) {
		ret.x = 0;
		ret.y = 0;
		ret.z = 0;
	} else {
		ret.x = ret.x * REPULSION_POWER;
		ret.y = ret.y * REPULSION_POWER;
		ret.z = ret.z * REPULSION_POWER;
	}
	return ret;
}

loc attraction(loc sun, loc planet) {
	loc ret = vector(planet, sun);
//	printf("vector: %f, %f, %f\n", ret.x, ret.y, ret.z);
	const float distance = length(ret);
	float multiplier;

	if(distance > OPTIMAL_DISTANCE + TOLERANCE) {
		multiplier = distance / 10;
	} else if(distance < OPTIMAL_DISTANCE - TOLERANCE) {
		multiplier = 0 - distance / 4;
	} else {
		multiplier = 0;
	}

	ret.x = ret.x * multiplier;
	ret.y = ret.y * multiplier;
	ret.z = ret.z * multiplier;

	return ret;
}

loc vector(loc from, loc to) {
	loc ret;
	ret.x = from.x - to.x;
	ret.y = from.y - to.y;
	ret.z = from.z - to.z;
	return ret;
}

float length(loc l) {
	return sqrt( sqr(l.x) + sqr(l.y) + sqr(l.z) );
}

loc add(loc first, loc second) {
	loc ret;
	ret.x = first.x + second.x;
	ret.y = first.y + second.y;
	ret.z = first.z + second.z;
	return ret;
}

loc sub(loc first, loc second) {
	loc ret;
	ret.x = first.x - second.x;
	ret.y = first.y - second.y;
	ret.z = first.z - second.z;
	return ret;
}
